package com.fits.gateway.api.config;

import cn.hutool.core.util.ArrayUtil;
import com.fits.gateway.api.filters.IgnoreFilterConfig;
import com.fits.gateway.api.handler.RestAuthenticationEntryPoint;
import com.fits.gateway.api.handler.RestfulAccessDeniedHandler;
import com.fits.gateway.api.props.IgnoreUrlProperties;
import com.nimbusds.jose.JWSObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

/**
 * 资源服务器配置
 *
 * @author lzy
 * @since 16:04 2024/7/4
 */
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
    @Autowired
    private IgnoreFilterConfig ignoreFilterConfig;
    @Autowired
    public IgnoreUrlProperties ignoreUrlProperties;
    @Autowired
    private AuthorizationManager authorizationManager;
    @Autowired
    private RestfulAccessDeniedHandler accessDeniedHandler;
    @Autowired
    private RestAuthenticationEntryPoint authenticationEntryPoint;

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
        httpSecurity.addFilterBefore(ignoreFilterConfig, SecurityWebFiltersOrder.AUTHENTICATION);
        httpSecurity.oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(jwtAuthenticationConverter());
        httpSecurity.authorizeExchange()
                //白名单放行
                .pathMatchers(ArrayUtil.toArray(ignoreUrlProperties.getUrls(), String.class)).permitAll()
                //其他请求，使用自定义的鉴权管理器
                .anyExchange().access(authorizationManager)
                .and()
                //异常处理器
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                //登录表单提交时，不需要带token
                .csrf().disable();
        return httpSecurity.build();
    }


    private Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
        // 从jwt 中获取该令牌可以访问的权限
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        // 取消权限的前缀，默认会加上SCOPE_
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");
        //jwt生成的token,解析出来，会带权限字段authorities为权限字段。字段名不能更改
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
    }
}
